package array.medium;


import java.util.Arrays;

/**
 * 在D天内送达包裹的能力
 *
 * 示例 1：
 *
 * 输入：weights = [1,2,3,4,5,6,7,8,9,10], D = 5
 * 输出：15
 * 解释：
 * 船舶最低载重 15 就能够在 5 天内送达所有包裹，如下所示：
 * 第 1 天：1, 2, 3, 4, 5
 * 第 2 天：6, 7
 * 第 3 天：8
 * 第 4 天：9
 * 第 5 天：10
 *
 * 请注意，货物必须按照给定的顺序装运，因此使用载重能力为 14 的船舶并将包装分成 (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) 是不允许的。
 * 示例 2：
 *
 * 输入：weights = [3,2,2,4,1,4], D = 3
 * 输出：6
 * 解释：
 * 船舶最低载重 6 就能够在 3 天内送达所有包裹，如下所示：
 * 第 1 天：3, 2
 * 第 2 天：2, 4
 * 第 3 天：1, 4
 * 示例 3：
 *
 * 输入：weights = [1,2,3,1,1], D = 4
 * 输出：3
 * 解释：
 * 第 1 天：1
 * 第 2 天：2
 * 第 3 天：3
 * 第 4 天：1, 1
 *
 * 链接：https://leetcode-cn.com/problems/capacity-to-ship-packages-within-d-days
 */
public class CapacityToShipPackagesWithinDDays_1011 {

    /**
     * 理论最低运力：只确保所有包裹能够被运送，自然也包括重量最大的包裹，此时理论最低运力为 max，max 为数组 weights 中的最大值
     * 理论最高运力：使得所有包裹在最短时间（一天）内运送完成，此时理论最高运力为 sum，sum 为数组 weights 的总和
     * @param weights
     * @param days
     * @return
     */
    public int shipWithinDays(int[] weights, int days) {

        int sum = Arrays.stream(weights).sum();
        int max = Arrays.stream(weights).max().getAsInt();
        //在区间[max, sum] 搜索。
        int l = max, r = sum;
        while(l < r) {
            int mid = (l + r) >> 1;
            if (this.verification(weights, mid, days)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return l;
    }

    public boolean verification(int[] weight, int t, int d) {
        int cd = 1;
        int sum = weight[0];
        for (int i = 1; i < weight.length; cd++) {
            while(i < weight.length && sum + weight[i] <= t) {
                sum += weight[i];
                i++;
            }
            sum = 0;
        }
        //凡是大于天数，说明拆包严重
        return cd - 1 <= d;
    }

}
